package physgin;

import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior;
import java.awt.GraphicsConfiguration;
import java.awt.Component;
import javax.swing.JFrame;

/**
 * Implements a world using the J3D library
 * for representing its structure in the scene
 * graph and drawing.
 */
public class J3dWorld extends World<J3dBackground, J3dBody, Canvas3D> 
    {
        private SimpleUniverse u;
        private BranchGroup scene;
        private Canvas3D c;
        private GraphicsConfiguration config;
        private J3dBackground b;
        
        /**
         * A cache for Textures used in the world.
         * @see     J3dTextureCache
         */
        static J3dTextureCache TextureCache = new J3dTextureCache();
        
        /**
         * Default constructor.
         */
        public J3dWorld()
        {
            config = SimpleUniverse.getPreferredConfiguration();
            c = new Canvas3D(config);
            u = new SimpleUniverse(c);
            
            u.getViewingPlatform().setNominalViewingTransform();
            u.getViewer().getPhysicalBody().setNominalEyeHeightFromGround(0.15f);
            u.getViewingPlatform().getViewPlatform().setViewAttachPolicy(View.NOMINAL_FEET);
            
            scene = createSceneGraph();
            u.addBranchGraph(scene);
            
            b = new J3dBackground();
        }
        
        private BranchGroup createSceneGraph()
        {
            BranchGroup objRoot = new BranchGroup();
            objRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
            objRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
            
            BoundingSphere bounds =
            new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000.0);
            
            Color3f ambientColor = new Color3f(1.0f, 1.0f, 1.0f);
            AmbientLight ambientLightNode = new AmbientLight(ambientColor);
            ambientLightNode.setInfluencingBounds(bounds);
            objRoot.addChild(ambientLightNode);
            
            Color3f light1Color = new Color3f(1.0f, 1.0f, 1.0f);
            Vector3f light1Direction = new Vector3f(4.0f, 5.0f, -10.0f);
            DirectionalLight light1
            = new DirectionalLight(light1Color, light1Direction);
            light1.setInfluencingBounds(bounds);
            objRoot.addChild(light1);
            
            return objRoot;
        }
        
        /**
         * Sets the background of the world, as a 
         * J3dBackground object.
         *
         * @param   b   J3dBackground to set as the worlds background.
         * @see         J3dBackground
         */
        public void setBackground(J3dBackground b)
        {
            this.b = b;
            scene.addChild(b.getObject());
        }
        
        /**
         * Sets the background of the world to a picture
         * locted at the file specified.
         *
         * @param   f   String of the file to set as the worlds background.
         */
        public void setBackground(String f)
        {
            b.setBackground(f);
            scene.addChild(b.getObject());
        }
        
        /**
         * Updates the background picture to the file specified.
         *
         * @param   f   String of the file to set as the worlds background.
         */
        public void updateBackground(String f)
        {
            b.setBackground(f);
        }
        
        /**
         * Adds a Body of type J3dBody to the world.
         *
         * @param   d   J3dBody to add to the world.
         * @see         J3dBody
         */
        public void addBody(J3dBody d)
        {
            BranchGroup n = d.getObject();
            scene.addChild(n);
        }
        
        /**
         * Removes a Body of type J3dBody from the world.
         *
         * @param   d   J3dBody to remove from the world.
         * @see         J3dBody
         */
        public void removeBody(J3dBody d)
        {
            BranchGroup n = d.getObject();
            int i = scene.indexOfChild(n);
            scene.removeChild(i);
        }
        
        /**
         * Returns a viewable canvas of type Canvas3D of the world.
         *
         * @return      Canvas3D view of the world.
         * @see         javax.media.j3d.Canvas3D
         */
        public Canvas3D getCanvas()
        {
            return u.getViewer().getCanvas3D();
        }
        
        /**
         * Returns a frame containing a view of the world.
         *
         * @return      JFrame containing a view of the world.
         */
        public JFrame getJFrame()
        {
            return u.getViewer().getJFrame(0);
        }
    }